import asyncio,time

#yield翻译为让渡，可以简单理解为暂停，并返回值
'''
列表：一次返回所有的元素，占用内存大
list(range(10))
什么是迭代器：一次可以只返回一个元素，占用很小的内存，读取大文件和数据集合时非常有用
iter(range(1))
迭代器可以用来表示数据流，提供惰性返回功能（即只有主动使用next方法调用一次迭代器，他才会返回一个数据）
当调用次数大于迭代器长度时，会报StopIteration错
'''
l_1=list(range(10))
# print(l_1)
i_1=iter(range(10))
# print(next(i_1))

'''
什么是生成器：生成器是一种特殊的迭代器，但他在迭代器惰性返回数据的基础上，提供了额外的功能，比如可以计算
yield 'sss',i
只要函数中有关键字yield，他就是生成器
'''
def a(n):
    for i in range(n):
        print('i:',i)
        yield 'sss',i
res = a(10)
# print('res:',next(res))
# print('res:',next(res))
# print('res:',next(res))

'''
迭代器和生成器的区别：迭代器侧重于对数据的惰性返回功能，生成器侧重于对指令的惰性返回功能
生成器指令：yield 'sss',i
'''

'''
协程的实现原理：跟生成器原理一样，但是在生成器的基础上增加了传递值的功能
'''
def b(a):
    print('a:',a)
    # 按照一般理解，此处的b值应为a，即是b=2
    # 但是作为协程，此处的b值是语句aa.send(3)中传递过来的值3，即b=3
    b = yield a
    print('b:',b)
    c = yield b
    print('c:',c)
    d = yield c
aa = b(2)
# 想要调用send方法，必须先调用next方法预激活生成器，使它停留在第一个yield的位置
# next(aa)
# aa.send(3)
# 实际上，print语句打印的是一个返回值，d
# print(aa.send(3))

'''
用协程实现一个计算平均数的函数
'''
def average_1():
    total = 0
    length = 0
    while True:
        try:
            value = yield total/length
        except ZeroDivisionError:
            value = yield 0
        total += value
        length += 1

average_2 = average_1()
# print(next(average_2))
# print(average_2.send(5))
# print(average_2.send(4))

'''
asyncio实现原理：自动维护一个事件队列，然后不断循环访问事件来完成异步的消息维护
替换yield from实现协程异步io，更好地实现异步程序
'''

# （不使用anyscio）模拟网络请求百度，返回的状态码是404
'''def statu_code():
    return 404
def request_baidu(index):
    print(f'模拟请求index：{index}')
    res = statu_code()
    print(f'状态码是：{res}')
    # 模拟网络延迟1s，由于当前线程是单线程，time.sleep(1)会阻塞线程1s
    time.sleep(1)
for i in range(10):
    request_baidu(i)
'''

# （使用anyscio）模拟网络请求百度，返回的状态码是404
def statu_code():
    return 404

async def request_baidu(index):
    res = statu_code()
    print(f'模拟请求index：{index}')
    # 模拟网络延迟1s，由于当前线程是单线程，time.sleep(1)会阻塞线程1s
    # time.sleep(1)
    print('-------------------------')
    # 先全部执行完上面代码
    await asyncio.sleep(1)
    # 1s后全部返回结果
    print('-------------------------')
    print(f'请求{index}状态码是：{res}')
    return res

# 获取事件队列
loop = asyncio.get_event_loop()

# 将request_baidu包装成任务
task_arr = []

# 往任务里添加事件
for i in range(100):
    task_arr.append(request_baidu(i))

# 循环访问任务
loop.run_until_complete(asyncio.wait(task_arr))

# 关闭事件
loop.close()